home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / color.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  20KB  |  846 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <stdio.h>
  16. #include <X11/Intrinsic.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xaw/Form.h>
  19. #include <X11/Xaw/Label.h>
  20. #include <X11/Xaw/Scrollbar.h>
  21. #include <X11/Xaw/AsciiText.h>
  22. #include <X11/Xaw/Command.h>
  23. #include <X11/Xaw/Text.h>
  24. #include <X11/StringDefs.h>
  25. #include <X11/cursorfont.h>
  26.  
  27. #ifndef NOSTDHDRS
  28. #include <stdlib.h>
  29. #include <unistd.h>
  30. #endif
  31.  
  32. #include "palette.h"
  33.  
  34. #include <math.h>
  35.  
  36. /*
  37. **  xpaint.h for MIN, MAX
  38. **  misc.h   for GetShell
  39. */
  40. #include "xpaint.h"
  41. #include "misc.h"
  42. #include "image.h"
  43.  
  44. #ifndef M_PI
  45. #define M_PI            3.14159265358979323846
  46. #endif
  47.  
  48. #define PIXMAP_WIDTH  120
  49. #define PIXMAP_HEIGHT 120
  50. #define RADIUS          50
  51.  
  52. #define RECOMPUTE(l)                            \
  53.         if (l->isRGB) {                        \
  54.             rgbTOhsv(l->r,l->g,l->b,&l->h,&l->s,&l->v);    \
  55.         } else {                        \
  56.             hsvTOrgb(l->h,l->s,l->v,&l->r,&l->g,&l->b);    \
  57.         }
  58.  
  59. typedef void    (*cbFunc_t)(Widget, XtPointer, Pixel);
  60.  
  61. typedef struct LocalInfo_s {
  62.     Boolean    initing, inCallback;
  63.     Widget    form;
  64.  
  65.     Widget    valueBar, redBar, greenBar, blueBar;
  66.  
  67.     /*
  68.     **  Color image picker widget, and delta x, y;
  69.     **   also a copy gc, and the image
  70.     */
  71.     GC        gc, xgc;
  72.     Pixmap        pixmap;
  73.     Widget        picker;
  74.     int        dx, dy;
  75.  
  76.     /*
  77.     **  Static current view
  78.     */
  79.     Widget        view;
  80.     Pixel        pixel;
  81.     Colormap    cmap;
  82.  
  83.     /*
  84.     **
  85.     */
  86.     Widget    valueText, redText, greenText, blueText;
  87.     Boolean    textChange;
  88.  
  89.     Boolean    isRGB;
  90.     float    h,s,v;
  91.     float    r,g,b;
  92.  
  93.     Palette            *map;
  94.     cbFunc_t        func;
  95.     XtPointer        data;
  96.  
  97.     struct LocalInfo_s    *next;
  98. } LocalInfo;
  99.  
  100. static LocalInfo    *head = NULL;
  101.  
  102. static void rgbTOhsv(float r, float g, float b, float *h, float *s, float *v)
  103. {
  104.     float    max = MAX(r,MAX(g,b));
  105.     float    min = MIN(r,MIN(g,b));
  106.     float    delta;
  107.  
  108.     *v = max;
  109.     if (max != 0.0)
  110.         *s = (max - min) / max;
  111.     else
  112.         *s = 0.0;
  113.  
  114.     if (*s == 0) {
  115.         *h = 0;
  116.     } else {
  117.         delta = max - min;
  118.         if (r == max) 
  119.             *h = (g - b) / delta;
  120.         else if (g == max)
  121.             *h = 2 + (b - r) / delta;
  122.         else if (b == max)
  123.             *h = 4 + (r - g) / delta;
  124.         *h *= 60;
  125.         if (*h < 0.0)
  126.             *h += 360;
  127.     }
  128. }
  129.  
  130. static void hsvTOrgb(float h, float s, float v, float *r, float *g, float *b)
  131. {
  132.     int    i;
  133.     float    f,p,q,t;
  134.  
  135.     if (s == 0 && h == 0) {
  136.         *r = *g = *b = v;
  137.     } else {
  138.         if (h >= 360.0)
  139.             h = 0.0;
  140.         h /= 60.0;
  141.  
  142.         i = h;
  143.         f = h - i;
  144.         p = v * (1 - s);
  145.         q = v * (1 - (s * f));
  146.         t = v * (1 - (s * (1 - f)));
  147.         switch (i) {
  148.         case 0: *r = v; *g = t; *b = p; break;
  149.         case 1: *r = q; *g = v; *b = p; break;
  150.         case 2: *r = p; *g = v; *b = t; break;
  151.         case 3: *r = p; *g = q; *b = v; break;
  152.         case 4: *r = t; *g = p; *b = v; break;
  153.         case 5: *r = v; *g = p; *b = q; break;
  154.         }
  155.     }
  156. }
  157.  
  158. /*
  159. **  Event callback routines
  160. */
  161. static void drawCursor(LocalInfo *l, Boolean flag)
  162. {
  163.     Dimension    width, height;
  164.     int        sx, sy;
  165.  
  166.     if (!XtIsRealized(l->picker))
  167.         return;
  168.  
  169.     XtVaGetValues(l->picker, XtNwidth, &width, XtNheight, &height, NULL);
  170.  
  171.     sx = -l->dx - 3 + width / 2;
  172.     sy = -l->dy - 3 + height / 2;
  173.  
  174.     if (flag) {
  175.         XDrawArc(XtDisplay(l->picker), XtWindow(l->picker), l->xgc,
  176.                 sx, sy, 6, 6, 0, 360*64);
  177.     } else {
  178.         int    cx, cy;
  179.         cx = PIXMAP_WIDTH  / 2;
  180.         cy = PIXMAP_HEIGHT / 2;
  181.         
  182.         XCopyArea(XtDisplay(l->picker), l->pixmap, XtWindow(l->picker), l->gc,
  183.                 -l->dx + cx - 4, -l->dy + cy - 4,
  184.                 8, 8, sx - 1, sy - 1);
  185.     }
  186. }
  187.  
  188. static void update(LocalInfo *l, Boolean doSB, Boolean doText, Boolean doCursor)
  189. {
  190.     XColor    col;
  191.     Pixel    p;
  192.  
  193.     if (doSB) {
  194.         XawScrollbarSetThumb(l->valueBar, l->v, -1.0);
  195.         XawScrollbarSetThumb(l->redBar, l->r, -1.0);
  196.         XawScrollbarSetThumb(l->greenBar, l->g, -1.0);
  197.         XawScrollbarSetThumb(l->blueBar, l->b, -1.0);
  198.     }
  199.     if (doText) {
  200.         char    buf[20];
  201.  
  202.         sprintf(buf,"%5.3f",l->v);
  203.         XtVaSetValues(l->valueText, XtNstring, buf, NULL);
  204.         sprintf(buf,"%d",(int)(l->r * 255));
  205.         XtVaSetValues(l->redText, XtNstring, buf, NULL);
  206.         sprintf(buf,"%d",(int)(l->g * 255));
  207.         XtVaSetValues(l->greenText, XtNstring, buf, NULL);
  208.         sprintf(buf,"%d",(int)(l->b * 255));
  209.         XtVaSetValues(l->blueText, XtNstring, buf, NULL);
  210.     }
  211.     if (doCursor) {
  212.         drawCursor(l, False);
  213.  
  214.         l->dx = sin(l->h * M_PI / 180.0) * l->s * RADIUS;
  215.         l->dy = cos(l->h * M_PI / 180.0) * l->s * RADIUS;
  216.  
  217.         drawCursor(l, True);
  218.     }
  219.  
  220.     if (l->initing)
  221.         return;
  222.  
  223.     col.flags = DoRed|DoGreen|DoBlue;
  224.     col.red   = l->r * 0xffff;
  225.     col.green = l->g * 0xffff;
  226.     col.blue  = l->b * 0xffff;
  227.     col.pixel = l->pixel;
  228.     p         = l->pixel;
  229.     if (l->map == NULL) {
  230.         XStoreColor(XtDisplay(l->view), l->cmap, &col);
  231.     } else {
  232.         if (!l->map->readonly)
  233.             XStoreColor(XtDisplay(l->view), l->cmap, &col);
  234.         else
  235.             XtVaSetValues(l->view, XtNbackground, 
  236.                     p = PaletteAlloc(l->map, &col), NULL);
  237.     }
  238.     if (l->func != NULL) {
  239.         l->inCallback = True;
  240.         l->func(l->form, l->data, p);
  241.         l->inCallback = False;
  242.     }
  243. }
  244.  
  245. static void expose(Widget w, LocalInfo *l, XExposeEvent *event, Boolean *flg)
  246. {
  247.     Dimension    width, height;
  248.     int        dx, dy;
  249.  
  250.     XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
  251.  
  252.     dx = (PIXMAP_WIDTH - width)   / 2;
  253.     dy = (PIXMAP_HEIGHT - height) / 2;
  254.  
  255.     XCopyArea(XtDisplay(w), l->pixmap, XtWindow(w), l->gc,
  256.             event->x + dx, event->y + dy, 
  257.             event->width, event->height,
  258.             event->x, event->y);
  259.     drawCursor(l, True);
  260. }
  261.  
  262. static void motion(Widget w, LocalInfo *l, XEvent *event, Boolean *flg)
  263. {
  264.     Dimension    width, height;
  265.     int        cx, cy;
  266.     int        dx, dy, dx2, dy2;
  267.  
  268.     while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w), MotionNotify, (XEvent*)event));
  269.  
  270.     XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
  271.  
  272.     cx = width / 2;
  273.     cy = height / 2;
  274.  
  275.     if (event->type == ButtonPress) {
  276.         dx = cx - event->xbutton.x;
  277.         dy = cy - event->xbutton.y;
  278.     } else {
  279.         dx = cx - event->xmotion.x;
  280.         dy = cy - event->xmotion.y;
  281.     }
  282.     dx2 = dx * dx;
  283.     dy2 = dy * dy;
  284.  
  285.  
  286.     if (dx == 0 && dy == 0)
  287.         l->h = 0;
  288.     else if ((l->h = atan2((double)dx, (double)dy)) < 0.0)
  289.         l->h += 2*M_PI;
  290.     l->s = sqrt((double)(dx2 + dy2)) / RADIUS;
  291.     l->h *= 360.0 / (2*M_PI);
  292.  
  293.     if (l->s > 1.0) {
  294.         l->s = 1.0;
  295.         dx = sin(l->h * M_PI / 180.0) * RADIUS;
  296.         dy = cos(l->h * M_PI / 180.0) * RADIUS;
  297.     }
  298.  
  299.     drawCursor(l, False);
  300.     l->dx = dx;
  301.     l->dy = dy;
  302.     drawCursor(l, True);
  303.  
  304.     l->isRGB = False;
  305.     RECOMPUTE(l);
  306.     update(l, True, True, False);
  307. }
  308.  
  309. static void barCB(Widget w, LocalInfo *l, float *percent)
  310. {
  311.     if (l->redBar == w) {
  312.         l->r = *percent;
  313.         l->isRGB = True;
  314.         RECOMPUTE(l);
  315.     } else if (l->greenBar == w) {
  316.         l->g = *percent;
  317.         l->isRGB = True;
  318.         RECOMPUTE(l);
  319.     } else if (l->blueBar == w) {
  320.         l->b = *percent;
  321.         l->isRGB = True;
  322.         RECOMPUTE(l);
  323.     } else if (l->valueBar == w) {
  324.         l->v = *percent;
  325.         l->isRGB = False;
  326.         RECOMPUTE(l);
  327.     }
  328.  
  329.     update(l, True, True, l->isRGB);
  330. }
  331.  
  332. static void textExitCB(Widget w, LocalInfo *l, XtPointer junk)
  333. {
  334.     String    val;
  335.     int    v;
  336.  
  337. #if 0
  338.     if (!l->textChange)
  339.         return;
  340. #endif
  341.  
  342.     XtVaGetValues(w, XtNstring, &val, NULL);
  343.     if (w != l->valueText) {
  344.         v = atoi(val);
  345.         if (v > 255) {
  346.             v = 255;
  347.             XtVaSetValues(w, XtNstring, "255", NULL);
  348.         }
  349.         if (v < 0) {
  350.             v = 0;
  351.             XtVaSetValues(w, XtNstring, "0", NULL);
  352.         }
  353.  
  354.         if (w == l->redText) {
  355.             if ((int)(l->r * 255.0) == v)
  356.                 return;
  357.             l->r = v / 255.0;
  358.             l->isRGB = True;
  359.             RECOMPUTE(l);
  360.         }
  361.         if (w == l->greenText) {
  362.             if ((int)(l->g * 255.0) == v)
  363.                 return;
  364.             l->g = v / 255.0;
  365.             l->isRGB = True;
  366.             RECOMPUTE(l);
  367.         }
  368.         if (w == l->blueText) {
  369.             if ((int)(l->b * 255.0) == v)
  370.                 return;
  371.             l->b = v / 255.0;
  372.             l->isRGB = True;
  373.             RECOMPUTE(l);
  374.         }
  375.     } else {
  376.         float    f = atof(val);
  377.  
  378.         /*
  379.         **  Same to 3 decimal places?
  380.         */
  381.         if ((int)(f * 1000) == (int)(l->v * 1000))
  382.             return;
  383.  
  384.         l->v = f;
  385.         l->isRGB = False;
  386.         RECOMPUTE(l);
  387.     }
  388.  
  389.     update(l, True, True, l->isRGB);
  390.     l->textChange = False;
  391. }
  392.  
  393. static void textAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
  394. {
  395.     Widget        cpick;
  396.     LocalInfo       *l = head;
  397.  
  398.     cpick = w;
  399.     while (cpick != None && strcmp(XtName(cpick), "colorPicker") != 0)
  400.         cpick = XtParent(cpick);
  401.  
  402.     if (cpick == None)
  403.         return;
  404.  
  405.         for (; l != NULL && l->form != cpick; l = l->next);
  406.  
  407.     textExitCB(w, l, NULL);
  408. }
  409.  
  410. #if 0
  411. static void textCB(Widget w, LocalInfo *l, XtPointer junk)
  412. {
  413.     l->textChange = True;
  414. }
  415. #endif
  416.  
  417. /*
  418. **  Grab the pixel value from some other window
  419. **
  420. **   General strategy:
  421. **     Grab the cursor
  422. **     Wait for the up/down button event
  423. **     Lookup what window the event is over
  424. **     Query the pixel value
  425. **     Query the colormap of the window
  426. **     Query the rgb pixel value
  427. */
  428. static void grabCB(Widget w, LocalInfo *l, XtPointer junk)
  429. {
  430.     XColor            *xcol = DoGrabColor(w);
  431.  
  432.     l->isRGB = True;
  433.     l->r = (float)((xcol->red >> 8)   & 0xff) / (float)0xff;
  434.     l->g = (float)((xcol->green >> 8) & 0xff) / (float)0xff;
  435.     l->b = (float)((xcol->blue >> 8)  & 0xff) / (float)0xff;
  436.  
  437.     RECOMPUTE(l);
  438.     update(l, True, True, True);
  439. }
  440.  
  441. /*
  442. **  Create a nice little color wheel that we chan pick colors from
  443. **
  444. **   Create it as an Image so that we can compress it down to the
  445. **    supported number of colors, after we've allocated "perfect" ones
  446. **
  447. */
  448. static void drawInPixmap(Widget w, Palette *map, Colormap cmap, 
  449.                 Pixel bg, Pixmap pix, GC gc)
  450. {
  451.     XImage        *xim = XGetImage(XtDisplay(w), pix, 0, 0, 
  452.                         PIXMAP_WIDTH, PIXMAP_HEIGHT,
  453.                         AllPlanes, ZPixmap);
  454.     int        offX = PIXMAP_WIDTH / 2 - RADIUS;
  455.     int        offY = PIXMAP_HEIGHT / 2 - RADIUS;
  456.     float        r, g, b;
  457.     float        h, s;
  458.     int        x, y;
  459.     static Image    *image = NULL;
  460.     unsigned char    *ip;
  461.     int        i;
  462.     XColor        xcol[64];
  463.     Pixel        pval[XtNumber(xcol)];
  464.     int        backgroundIndex = 0;
  465.     Boolean        isTrue = (map != NULL && !map->isMapped);
  466.  
  467.     StateSetBusyWatch(True);
  468.  
  469.     if (image == NULL || isTrue) {
  470.         image = ImageNew(2 * RADIUS, 2 * RADIUS);
  471.         ip = image->data;
  472.  
  473.         for (y = 0; y < 2*RADIUS; y++) {
  474.             for (x = 0; x < 2*RADIUS; x++) {
  475.                 int    dx, dy, dx2, dy2;
  476.  
  477.                 dx = RADIUS - x;    dx2 = dx * dx;
  478.                 dy = RADIUS - y;    dy2 = dy * dy;
  479.  
  480.                 if (dx2 + dy2 > RADIUS*RADIUS) {
  481.                     *ip++ = 0;
  482.                     *ip++ = 0;
  483.                     *ip++ = 0;
  484.                     continue;
  485.                 }
  486.  
  487.                 if (dx == 0 && dy == 0)
  488.                     h = 0;
  489.                 else if ((h = atan2((double)dx, (double)dy)) < 0.0)
  490.                     h += 2*M_PI;
  491.                 s = sqrt((double)(dx2 + dy2)) / RADIUS;
  492.  
  493.                 h *= 360.0 / (2*M_PI);
  494.  
  495.                 hsvTOrgb(h, s, 1.0, &r, &g, &b);
  496.                 
  497.                 *ip++ = r * 255;
  498.                 *ip++ = g * 255;
  499.                 *ip++ = b * 255;
  500.                 if (isTrue) {
  501.                     XColor    c;
  502.                     c.red   = r * 0xffff;
  503.                     c.green = g * 0xffff;
  504.                     c.blue  = b * 0xffff;
  505.                     XPutPixel(xim, offX + x, offY + y, 
  506.                             PaletteAlloc(map, &c));
  507.                 }
  508.             }
  509.         }
  510.         if (isTrue) {
  511.             ImageDelete(image);
  512.             image = NULL;
  513.         } else {
  514.             image = ImageCompress(image, XtNumber(xcol));
  515.         }
  516.     }
  517.  
  518.     if (!isTrue) {
  519.         for (i = 0; i < image->cmapSize; i++) {
  520.             xcol[i].flags = DoRed|DoGreen|DoBlue;
  521.             xcol[i].red = image->cmapData[i*3+0] * 256;
  522.             xcol[i].green = image->cmapData[i*3+1] * 256;
  523.             xcol[i].blue = image->cmapData[i*3+2] * 256;
  524.             if (xcol[i].red == xcol[i].green && 
  525.                 xcol[i].green == xcol[i].blue &&
  526.                 xcol[i].red == 0) {
  527.                 backgroundIndex = i;
  528.                 continue;
  529.             }
  530.  
  531.             if (map == NULL) {
  532.                 XAllocColor(XtDisplay(w), cmap, &xcol[i]);
  533.                 pval[i] = xcol[i].pixel;
  534.             }
  535.         }
  536.     
  537.         if (map != NULL)
  538.             PaletteAllocN(map, xcol, image->cmapSize, pval);
  539.  
  540.         for (ip = image->data, y = 0; y < 2*RADIUS; y++) {
  541.             for (x = 0; x < 2*RADIUS; x++, ip++) {
  542.                 if (*ip == backgroundIndex)
  543.                     XPutPixel(xim, offX + x, offY + y, bg);
  544.                 else
  545.                     XPutPixel(xim, offX + x, offY + y, pval[*ip]);
  546.             }
  547.         }
  548.     }
  549.     
  550.     XPutImage(XtDisplay(w), pix, gc, xim, 0, 0, 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
  551.     XDestroyImage(xim);
  552.  
  553.     StateSetBusyWatch(False);
  554. }
  555.  
  556. static Widget createBarText(Widget parent, Widget above, String msg,
  557.                 Widget *bar, Widget *text)
  558. {
  559.     static String    textTranslations = "#override\n\
  560.                      <Key>Return: color-text-ok()\n\
  561.                      <Key>Linefeed: color-text-ok()\n\
  562.                      Ctrl<Key>M: color-text-ok()\n\
  563.                      Ctrl<Key>J: color-text-ok()\n";
  564.     static XtTranslations    trans = None;
  565.     Widget            subform, label;
  566.  
  567.     if (trans == None) {
  568.         static XtActionsRec     act = { "color-text-ok", (XtActionProc)textAction };
  569.  
  570.         XtAppAddActions(XtWidgetToApplicationContext(parent), &act, 1);
  571.  
  572.         trans = XtParseTranslationTable(textTranslations);
  573.     }
  574.  
  575.     subform = XtVaCreateManagedWidget("form", formWidgetClass, parent, 
  576.                 XtNborderWidth, 0,
  577.                 XtNfromVert, above,
  578.                 NULL);
  579.     label = XtVaCreateManagedWidget("valueLabel", labelWidgetClass, subform,
  580.                 XtNlabel, msg,
  581.                 XtNborderWidth, 0,
  582.                 XtNright, XtChainLeft,
  583.                 XtNleft, XtChainLeft,
  584.                 NULL);
  585.     *bar = XtVaCreateManagedWidget("valueBar", scrollbarWidgetClass, subform,
  586.                 XtNorientation, XtorientHorizontal,
  587.                 XtNlength, 200,
  588.                 XtNfromHoriz, label,
  589.                 XtNleft, XtChainLeft,
  590.                 NULL);
  591.     *text = XtVaCreateManagedWidget("valueText", asciiTextWidgetClass, subform,
  592.                 XtNfromHoriz, *bar,
  593.                 XtNeditType, XawtextEdit,
  594.                 XtNwrap, XawtextWrapNever,
  595.                 XtNresize, XawtextResizeWidth,
  596.                 XtNtranslations, trans,
  597.                 XtNwidth, 50,
  598.                 XtNlength, 5,
  599.                 NULL);
  600.     return subform;
  601. }
  602.  
  603. static void freePixel(Widget w, LocalInfo *l)
  604. {
  605.     XFreeColors(XtDisplay(w), l->cmap, &l->pixel, 1, 0);
  606. }
  607.  
  608. static LocalInfo *colorPicker(Widget parent, Colormap cmap, Pixel *pixval)
  609. {
  610.     Widget        top = GetToplevel(parent);
  611.     Widget        form, picker, subform;
  612.     Widget        button;
  613.     LocalInfo    *l = (LocalInfo*)XtNew(LocalInfo);
  614.     XGCValues    gcvalues;
  615.  
  616.     if (cmap == None)
  617.         cmap = DefaultColormapOfScreen(XtScreen(parent));
  618.  
  619.     l->initing = True;
  620.     l->inCallback = False;
  621.     l->func = NULL;
  622.     
  623.     l->cmap = cmap;
  624.  
  625.     form = XtVaCreateManagedWidget("colorPicker", formWidgetClass, parent, NULL);
  626.  
  627.     /*
  628.     **  The HS space image
  629.     */
  630.     picker = XtVaCreateManagedWidget("palette", coreWidgetClass, form, 
  631.                 XtNwidth, PIXMAP_WIDTH,
  632.                 XtNheight, PIXMAP_WIDTH,
  633.                 NULL);
  634.     l->picker = picker;
  635.  
  636.     XtAddEventHandler(picker, ExposureMask, False, (XtEventHandler)expose, (XtPointer)l);
  637.     XtAddEventHandler(picker, ButtonPressMask, False, (XtEventHandler)motion, (XtPointer)l);
  638.     XtAddEventHandler(picker, ButtonMotionMask, False, (XtEventHandler)motion, (XtPointer)l);
  639.  
  640.     gcvalues.foreground = BlackPixel(XtDisplay(top), DefaultScreen(XtDisplay(top)));
  641.     l->xgc = XtGetGC(picker, GCForeground, &gcvalues);
  642.  
  643.     /*
  644.     **  The color "view"
  645.     */
  646.     l->pixel = None;
  647.     if (pixval == NULL) {
  648.         if (XAllocColorCells(XtDisplay(top), cmap, False, NULL, 0, &l->pixel, 1)) {
  649.             XColor    col;
  650.             col.pixel = l->pixel;
  651.             col.flags = DoRed|DoGreen|DoBlue;
  652.             col.red   = 0xffff;
  653.             col.green = 0xffff;
  654.             col.blue  = 0xffff;
  655.             XStoreColor(XtDisplay(top), cmap, &col);
  656.  
  657.                 XtAddCallback(form, XtNdestroyCallback, (XtCallbackProc)freePixel, (XtPointer)l);
  658.         }
  659.     } else {
  660.         l->pixel = *pixval;
  661.     }
  662.     l->view = XtVaCreateManagedWidget("view", coreWidgetClass, form,
  663.                 XtNwidth, 40,
  664.                 XtNheight, 40,
  665.                 XtNfromHoriz, picker,
  666.                 XtNbackground, l->pixel,
  667.                 NULL);
  668.  
  669.     button = XtVaCreateManagedWidget("match", commandWidgetClass, form,
  670.                 XtNfromVert, l->view,
  671.                 XtNfromHoriz, picker,
  672.                 NULL);
  673.     XtAddCallback(button, XtNcallback, (XtCallbackProc)grabCB, (XtPointer)l);
  674.             
  675.     /*
  676.     **  Now create the scroll bars
  677.     */
  678.     subform = createBarText(form, picker,  "Value", &l->valueBar, &l->valueText);
  679.     subform = createBarText(form, subform, "Red", &l->redBar, &l->redText);
  680.     subform = createBarText(form, subform, "Green", &l->greenBar, &l->greenText);
  681.     subform = createBarText(form, subform, "Blue", &l->blueBar, &l->blueText);
  682.  
  683.     XtAddCallback(l->valueBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
  684.     XtAddCallback(l->redBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
  685.     XtAddCallback(l->greenBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
  686.     XtAddCallback(l->blueBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
  687.  
  688. #if 0
  689.     XtAddCallback(l->valueText, XtNcallback, (XtCallbackProc)textCB, (XtPointer)l);
  690.     XtAddCallback(l->redText,   XtNcallback, (XtCallbackProc)textCB, (XtPointer)l);
  691.     XtAddCallback(l->greenText, XtNcallback, (XtCallbackProc)textCB, (XtPointer)l);
  692.     XtAddCallback(l->blueText,  XtNcallback, (XtCallbackProc)textCB, (XtPointer)l);
  693. #endif
  694.  
  695.     l->textChange = False;
  696.     l->isRGB = True;
  697.     l->r = l->g = l->b = 1.0;
  698.     RECOMPUTE(l);
  699.     update(l, True, True, True);
  700.  
  701.     l->form = form;
  702.     l->next = head;
  703.     head = l;
  704.  
  705.     return l;
  706. }
  707.  
  708. Widget ColorPickerPalette(Widget parent, Palette *map, Pixel *pixval)
  709. {
  710.     LocalInfo    *l = colorPicker(parent, map->cmap, pixval);
  711.     XGCValues    gcvalues;
  712.     Cardinal    depth;
  713.  
  714.     XtVaGetValues(l->picker, XtNbackground, &gcvalues.foreground, XtNdepth, &depth, NULL);
  715.     l->pixmap = XCreatePixmap(XtDisplay(l->picker), 
  716.                 DefaultRootWindow(XtDisplay(l->picker)), 
  717.                 PIXMAP_WIDTH, PIXMAP_HEIGHT, depth);
  718.     l->gc = XtGetGC(l->picker, GCForeground, &gcvalues);
  719.     XFillRectangle(XtDisplay(l->picker), l->pixmap, l->gc, 
  720.                 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
  721.     l->map = map;
  722.     drawInPixmap(l->picker, map, l->cmap, gcvalues.foreground, l->pixmap, l->gc);
  723.  
  724.     l->initing = False;
  725.     return l->form;
  726. }
  727.  
  728. Widget ColorPicker(Widget parent, Colormap cmap, Pixel *pixval)
  729. {
  730.     LocalInfo    *l = colorPicker(parent, cmap, pixval);
  731.     XGCValues    gcvalues;
  732.     Cardinal    depth;
  733.  
  734.     l->map = NULL;
  735.  
  736.     XtVaGetValues(l->picker, XtNbackground, &gcvalues.foreground, XtNdepth, &depth, NULL);
  737.     l->pixmap = XCreatePixmap(XtDisplay(l->picker), 
  738.                 DefaultRootWindow(XtDisplay(l->picker)), 
  739.                 PIXMAP_WIDTH, PIXMAP_HEIGHT, depth);
  740.     l->gc = XtGetGC(l->picker, GCForeground, &gcvalues);
  741.     XFillRectangle(XtDisplay(l->picker), l->pixmap, l->gc, 
  742.                 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
  743.     drawInPixmap(l->picker, NULL, l->cmap, gcvalues.foreground, l->pixmap, l->gc);
  744.  
  745.     l->initing = False;
  746.     return l->form;
  747. }
  748.  
  749. void ColorPickerShell(Widget w)
  750. {
  751.     Widget        top = GetToplevel(w);
  752.     Widget        shell;
  753.     Colormap    cmap = DefaultColormapOfScreen(XtScreen(top));
  754.  
  755.     shell = XtVaCreatePopupShell("color", transientShellWidgetClass, 
  756.                     GetShell(w), NULL);
  757.  
  758.     ColorPicker(shell, cmap, NULL);
  759.  
  760.     XtPopup(shell, XtGrabNone);
  761. }
  762.  
  763. void ColorPickerSetXColor(Widget w, XColor *xcol)
  764. {
  765.     LocalInfo    *l = head;
  766.  
  767.     for (; l != NULL && l->form != w; l = l->next);
  768.  
  769.     if (l == NULL || l->inCallback)
  770.         return;
  771.  
  772.     l->isRGB = True;
  773.     l->r = (float)((xcol->red >> 8)   & 0xff) / (float)0xff;
  774.     l->g = (float)((xcol->green >> 8) & 0xff) / (float)0xff;
  775.     l->b = (float)((xcol->blue >> 8)  & 0xff) / (float)0xff;
  776.  
  777.     RECOMPUTE(l);
  778.     update(l, True, True, True);
  779. }
  780.  
  781. void ColorPickerSetPixel(Widget w, Pixel pix)
  782. {
  783.     LocalInfo    *l = head;
  784.     XColor        xcol;
  785.  
  786.     for (; l != NULL && l->form != w; l = l->next);
  787.  
  788.     if (l == NULL || l->inCallback)
  789.         return;
  790.  
  791.     XtVaSetValues(l->view, XtNbackground, pix, NULL);
  792.  
  793.     xcol.pixel = pix;
  794.     XQueryColor(XtDisplay(w), l->cmap, &xcol);
  795.  
  796.     l->isRGB = True;
  797.     l->r = (float)((xcol.red >> 8)   & 0xff) / (float)0xff;
  798.     l->g = (float)((xcol.green >> 8) & 0xff) / (float)0xff;
  799.     l->b = (float)((xcol.blue >> 8)  & 0xff) / (float)0xff;
  800.     l->pixel = pix;
  801.  
  802.     RECOMPUTE(l);
  803.     update(l, True, True, True);
  804. }
  805.  
  806. void ColorPickerSetFunction(Widget w, XtCallbackProc func, XtPointer data)
  807. {
  808.     LocalInfo    *l = head;
  809.  
  810.     for (; l != NULL && l->form != w; l = l->next);
  811.  
  812.     if (l == NULL)
  813.         return;
  814.  
  815.     l->func = (cbFunc_t)func;
  816.     l->data = data;
  817. }
  818.  
  819. Pixel ColorPickerGetPixel(Widget w)
  820. {
  821.     LocalInfo    *l = head;
  822.  
  823.     for (; l != NULL && l->form != w; l = l->next);
  824.  
  825.     if (l == NULL)
  826.         return None;
  827.     return l->pixel;
  828. }
  829.  
  830. XColor *ColorPickerGetXColor(Widget w)
  831. {
  832.     static XColor    xcol;
  833.     LocalInfo    *l = head;
  834.  
  835.     for (; l != NULL && l->form != w; l = l->next);
  836.  
  837.     if (l == NULL)
  838.         return NULL;
  839.     xcol.pixel = l->pixel;
  840.     xcol.red   = l->r * 0xffff;
  841.     xcol.green = l->g * 0xffff;
  842.     xcol.blue  = l->b * 0xffff;
  843.  
  844.     return &xcol;
  845. }
  846.